﻿/**	@file		bounds.hpp
 *	@date		(2011-08-14 12:31:11)/(2011-08-14 12:31:12)
 *-----------------------------------------------------------------------------
 *	\brief		Some Bound Type.
 *	@version	1.0.1.1
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__SOLA__BOUNDS__NICK__K_IN_G__)
#define		__LOLIX__SOLA__BOUNDS__NICK__K_IN_G__

#if			!defined(__LOLIX__TOY__L_X_ASSERT_NICK__K_IN_G__)
	#include	"../toy/lx_assert.h"
#endif	//	!defined(__LOLIX__TOY__L_X_ASSERT_NICK__K_IN_G__)

#if			!defined(__LOLIX__SOLA__VEC__NICK__K_IN_G__)
	#include	"./vec.hpp"
#endif	//	!defined(__LOLIX__SOLA__VEC__NICK__K_IN_G__)

namespace lolix{namespace sola{
	template<typename _Ty>
	class aabb
	{
		vec<3, _Ty> _min;
		vec<3, _Ty> _size;
	public:
		typedef vec<3, _Ty> position_type;
		typedef vec<3, _Ty> size_type;
		LOLIX_INLINE_CALL aabb(void){}
		LOLIX_INLINE_CALL aabb(position_type const& min_pos, size_type const& size)
			: _min(min_pos)
			, _size(size)
		{
			LOLIX_ASSERT(size.x >= 0, L"x 大小错误");
			LOLIX_ASSERT(size.y >= 0, L"y 大小错误");
			LOLIX_ASSERT(size.z >= 0, L"z 大小错误");
		}

		LOLIX_INLINE_CALL size_type const& size(void)const{return _size;}
		LOLIX_INLINE_CALL void size(size_type const& new_size){_size = new_size;}
		LOLIX_INLINE_CALL void size(_Ty x, _Ty y, _Ty z){_size(x, y, z);}

		LOLIX_INLINE_CALL position_type const& min_pos(void)const{return _min;}
		LOLIX_INLINE_CALL void min_pos(position_type const& new_min){_min = new_min;}
		LOLIX_INLINE_CALL void min_pos(_Ty x, _Ty y, _Ty z){_min(x, y, z);}
		LOLIX_INLINE_CALL const position_type max_pos(void)const{return _min + _size;}

		template<typename _Tp>
		LOLIX_INLINE_CALL void move(const _Tp& dis){_min += dis;}
	};

	template<typename _Ty>
	class bound_ball
	{
		vec<4, _Ty> _ball;
	public:
		LOLIX_INLINE_CALL bound_ball(void){}
		LOLIX_INLINE_CALL bound_ball(_Ty x, _Ty y, _Ty z, _Ty r): _ball(x, y, z, r){ }
		LOLIX_INLINE_CALL bound_ball(vec<3, _Ty> const& center, _Ty radius): _ball(center, radius){ }
		LOLIX_INLINE_CALL bound_ball(vec<4, _Ty> const& b): _ball(b){ }
		LOLIX_INLINE_CALL _Ty radius(void)const{return _ball.w;}
		LOLIX_INLINE_CALL void radius(_Ty r){_ball.w = r;}
		LOLIX_INLINE_CALL vec<3, _Ty> const& center(void)const{return reinterpret_cast<vec<3, _Ty> const&>(_ball);}
		template<typename _Tp>
		LOLIX_INLINE_CALL void center(_Tp const& center){ (vec<3, _Ty>&)_ball = center;}
		LOLIX_INLINE_CALL void center(_Ty x, _Ty y, _Ty z){_ball.x = x; _ball.y = y; _ball.z = z;}

		template<typename _Tp>
		LOLIX_INLINE_CALL void move(const _Tp& dis){_ball.x += dis.x; _ball.y += dis.y; _ball.z += dis.z;}
	};

	enum ENUM_INTERSECTING_TYPE
	{	INTERSECTION_TYPE_NONE		//	相离
	,	INTERSECTION_TYPE_INCLUDE	//	包含
	,	INTERSECTION_TYPE_INSIDE	//	被包含
	,	INTERSECTION_TYPE_CROSS		//	相交
	};

	template<typename _Ta, typename _Tb>
	LOLIX_INLINE_CALL ENUM_INTERSECTING_TYPE check_intersection(bound_ball<_Ta> const& a, bound_ball<_Tb> const& b)
	{
		auto o = a.center() - b.center();
		auto vo = o.size_p2();
		auto v = a.radius() + b.radius();
		v *= v;
		if ( vo > v )	//	两个圆相离
			return INTERSECTION_TYPE_NONE;

		auto lr = b.radius() - a.radius();
		auto lr_p2 = lr * lr;
		if ( lr_p2 < vo )
			return lr > 0
				? INTERSECTION_TYPE_INSIDE
				: INTERSECTION_TYPE_INCLUDE
				;

		return INTERSECTION_TYPE_CROSS;
	}

	template<typename _Ta, typename _Tb>
	LOLIX_INLINE_CALL ENUM_INTERSECTING_TYPE check_intersection(aabb<_Ta> const& a, bound_ball<_Tb> const& b)
	{
		//	如果中心相隔太远则认为相离
		const auto box_radius = a.size()/(_Ta)2;
		auto box_center = a.min_pos() + box_radius;
		const auto center_length_p2 = (box_center - b.center()).size_p2();
		const auto outer_radius_p2 = box_radius.size_p2() + b.radius() * b.radius();
		//auto outer_radius_p2 = outer_radius * outer_radius;
		if ( center_length_p2 >= outer_radius_p2 )
			return INTERSECTION_TYPE_NONE;
		//	否则要检查, 包围盒的哪几个面可能和球相交
		//	将坐标轴的源点移动到包围盒的中心, 然后圆的中心移动过后全部取为正(轴对称图形的判定嘛)
		//	忽略掉包围盒， 仅需要判定一个 a.size, 和 b 的半径以及对应位置
		//	此时， 仅需要判定三个面：正面，顶面，与右面 : 右手坐标系， 不过这个描述是数字空间描述，无关乎于3维空间
		//const auto& box_size = a.size();
		bool is_include = true;
		bool is_inside = true;
		for ( size_type i = 0; i != 3 ; ++i )
		{
			const auto tmp = abs(b.center()[i] - box_center[i]);
			if ( tmp - box_radius[i] > b.radius() )
				return INTERSECTION_TYPE_NONE;

			if ( is_include || is_inside )
			{
				if ( tmp > box_radius[i] - b.radius() )
					is_include = false;
				if ( tmp > b.radius() - box_radius[i] )
					is_inside = false;
			}
		}

		if ( is_include )
			return INTERSECTION_TYPE_INCLUDE;

		if ( is_inside )
			return INTERSECTION_TYPE_INSIDE;

		return INTERSECTION_TYPE_CROSS;
	}

	template<typename _Ta, typename _Tb>
	LOLIX_INLINE_CALL ENUM_INTERSECTING_TYPE check_intersection(bound_ball<_Ta> const& a, aabb<_Tb> const& b)
	{
		ENUM_INTERSECTING_TYPE e = check_intersection(b, a);
		return (ENUM_INTERSECTING_TYPE)((e >> 1) | ((e & 1) << 1));
	}

	template<typename _Ta, typename _Tb>
	LOLIX_INLINE_CALL ENUM_INTERSECTING_TYPE check_intersection(aabb<_Ta> const& a, aabb<_Tb> const& b)
	{
		const auto a_min = a.min_pos();
		const auto a_max = a.max_pos();
		const auto b_min = b.min_pos();
		const auto b_max = b.max_pos();
		bool is_include = true;
		bool is_inside = true;
		for ( size_type i = 0; i != 3; ++i )
		{
			//	out 判断
			if ( a_min[i] < b_min[i] )
			{
				if ( a_max[i] <= b_min[i] )
					return INTERSECTION_TYPE_NONE;
				if ( a_max[i] < b_max[i] )
					is_include = false;
			}
			else
			{
				if ( b_max[i] < a_min[i] )
					return INTERSECTION_TYPE_NONE;
				if ( b_max[i] < a_max[i] )
					is_inside = false;
			}
		}

		if ( is_include )
			return INTERSECTION_TYPE_INCLUDE;

		if ( is_inside )
			return INTERSECTION_TYPE_INSIDE;

		return INTERSECTION_TYPE_CROSS;
	}
}}

#endif	//	!defined(__LOLIX__SOLA__BOUNDS__NICK__K_IN_G__)
